package com.peoit.honeycomb.application.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.transaction.Transactional;

import com.peoit.honeycomb.domain.security.Person;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.peoit.honeycomb.application.UserApplication;
import com.peoit.honeycomb.domain.HoneycombProject;
import com.peoit.honeycomb.domain.SmsTemplate;
import com.peoit.honeycomb.domain.User;
import com.peoit.honeycomb.domain.exception.DuplicatedEmailException;
import com.peoit.honeycomb.domain.exception.DuplicatedMobileException;
import com.peoit.honeycomb.domain.exception.DuplicatedUserNameException;
import com.peoit.honeycomb.domain.exception.EmailExistException;
import com.peoit.honeycomb.domain.exception.LoginFailureException;
import com.peoit.honeycomb.domain.exception.SmsTemplateNotExistException;
import com.peoit.honeycomb.domain.exception.UserNotExistException;
import com.peoit.honeycomb.domain.exception.WrongPasswordException;
import com.peoit.honeycomb.domain.repository.HibernateEntityRepository;
import com.peoit.honeycomb.dto.Config;
import com.peoit.honeycomb.dto.UserQueryDto;
import com.peoit.honeycomb.dto.UserRealNameVerifyDto;
import com.peoit.honeycomb.util.CommonUtil;

/**
 * Created by Bing.Zeng on 2015/9/24.
 */
@Service
public class UserApplicationImpl extends HibernateEntityRepository implements UserApplication {
	/**
	 * 根据条件分页查询 user
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public List<User> findByWherePage(UserQueryDto dto) {

		int pageSize = dto.getPageSize();
		int offset = dto.getOffset();

		List<Object> parameters = new ArrayList<>();

		StringBuffer where = new StringBuffer("");

		if (!StringUtils.isEmpty(dto.getUserName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" userName like ? ");
			parameters.add("%" + dto.getUserName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getEmail())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" email like ? ");
			parameters.add("%" + dto.getEmail() + "%");
		}
		if (!StringUtils.isEmpty(dto.getPhoneNumber())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" phoneNumber like ? ");
			parameters.add("%" + dto.getPhoneNumber() + "%");
		}
		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" 1=1 order by createTime desc");

		List<User> result = queryByWherePage(User.class, where.toString(), CommonUtil.listToArray(parameters), offset,
				pageSize);
		return result;
	}

	/**
	 * 查询用户数量
	 * 
	 * @param dto
	 * @return
	 */
	public Long findUserCount(UserQueryDto dto) {
		List<Object> parameters = new ArrayList<>();

		StringBuffer where = new StringBuffer("");

		if (!StringUtils.isEmpty(dto.getUserName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" userName like ? ");
			parameters.add("%" + dto.getUserName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getEmail())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" email like ? ");
			parameters.add("%" + dto.getEmail() + "%");
		}
		if (!StringUtils.isEmpty(dto.getPhoneNumber())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" phoneNumber like ? ");
			parameters.add("%" + dto.getPhoneNumber() + "%");
		}
		return getCountByWhere(User.class, where.toString(), CommonUtil.listToArray(parameters));
	}

	@Override
	public User getUserById(String id) {
		User user = find(User.class, id);
		return user;
	}

	@Override
	@Transactional
	public User updateUser(User user) {

		String where = "id NOT IN ('" + user.getId() + "') AND phoneNumber = ?  ";
		Object[] parameters = { user.getPhoneNumber() };
		boolean existMobile = isExistedByWhere(User.class, where, parameters);

		if (existMobile) {
			throw new DuplicatedMobileException();
		}

		where = "id NOT IN ('" + user.getId() + "') AND  userName = ?  ";
		parameters = new Object[] { user.getUserName() };

		boolean existUserName = isExistedByWhere(User.class, where, parameters);
		if (existUserName) {
			throw new DuplicatedUserNameException();
		}
		User oldUser = find(User.class, user.getId());
		oldUser.setPhoneNumber(user.getPhoneNumber());
		oldUser.setUserName(user.getUserName());
		oldUser.setPassword(user.getPassword());
		oldUser.setAuthorizationCode(user.getAuthorizationCode());
		update(oldUser);
		return user;
	}

	@Transactional
	public User register(User user) {

		String where = " phoneNumber = ?  ";
		Object[] parameters = { user.getPhoneNumber() };
		boolean existMobile = isExistedByWhere(User.class, where, parameters);

		if (existMobile) {
			throw new DuplicatedMobileException();
		}

		where = " userName = ?  ";
		parameters = new Object[] { user.getUserName() };

		boolean existUserName = isExistedByWhere(User.class, where, parameters);
		if (existUserName) {
			throw new DuplicatedUserNameException();
		}

		user = this.create(user);
		return user;
	}

	/**
	 * 登录
	 * 
	 * @param loginId
	 * @param password
	 * @return
	 */
	public User login(String loginId, String password) {
		String where = " ( userName = ? AND password = ? ) OR (phoneNumber = ? AND password = ?)  ";
		Object[] parameters = { loginId, password, loginId, password };
		User user = queryByWhereSingle(User.class, where, parameters);

		if (user == null) {
			throw new LoginFailureException();
		}

		return user;
	}

	/**
	 * 验证authorization
	 * 
	 * @param loginId
	 *            可以是用户名或者是电话号码
	 * @param authorizationCode
	 * @return
	 */
	public boolean verifyAuthorizationCode(String loginId, String authorizationCode) {
		boolean result = false;
		String where = " userName = ? OR phoneNumber = ?";
		Object[] parameters = { loginId, loginId };
		User user = queryByWhereSingle(User.class, where, parameters);
		if (user == null) {
			throw new UserNotExistException();
		} else {
			if (authorizationCode.equals(user.getAuthorizationCode())) {
				result = true;
			}

		}
		return result;
	}

	@Override
	public boolean checkUserNameExist(String userName) {
		String where = " userName =  ? ";
		Object[] parameters = { userName };

		return isExistedByWhere(User.class, where, parameters);
	}

	@Override
	public boolean checkPhoneNumberExist(String phoneNumber) {
		String where = " phoneNumber =  ? ";
		Object[] parameters = { phoneNumber };

		return isExistedByWhere(User.class, where, parameters);
	}

	/**
	 *
	 *
	 * 修改授权密码
	 *
	 *
	 * @param id
	 * @param oldPass
	 * @param newPass
	 * @return
	 *
	 *
	 */
	@Override
	@Transactional
	public boolean changeAuthCode(String id, String oldPass, String newPass) {
		User user = find(User.class, id);
		if (user == null) {
			throw new UserNotExistException();
		}
		if (!user.getAuthorizationCode().equals(oldPass)) {
			throw new WrongPasswordException();
		}
		user.setAuthorizationCode(newPass);
		update(user);
		return true;
	}

	/**
	 *
	 *
	 * 修改登陆密码
	 *
	 *
	 * @param id
	 * @param oldPass
	 * @param newPass
	 * @return
	 *
	 */
	@Override
	@Transactional
	public boolean changeLoginPass(String id, String oldPass, String newPass) {
		User user = find(User.class, id);
		if (user == null) {
			throw new UserNotExistException();
		}
		if (!user.getPassword().equals(oldPass)) {
			throw new WrongPasswordException();
		}
		user.setPassword(newPass);
		update(user);
		return true;
	}

	/**
	 * 重设授权密码
	 *
	 * @param id
	 * @param newPass
	 * @return
	 */
	@Override
	@Transactional
	public boolean resetAuthCode(String id, String newPass) {

		String whereSql = " id = ? or phoneNumber= ? ";
		Object[] queryParams = { id, id };
		User user = queryByWhereSingle(User.class, whereSql, queryParams);
		if (user == null) {
			throw new UserNotExistException();
		}

		user.setAuthorizationCode(newPass);
		update(user);
		return true;
	}

	/**
	 * 重设登录密码
	 *
	 * @param id
	 * @param newPass
	 * @return
	 */
	@Override
	@Transactional
	public boolean resetLoginPass(String id, String newPass) {
		String whereSql = " id = ? or phoneNumber= ? ";
		Object[] queryParams = { id, id };
		User user = queryByWhereSingle(User.class, whereSql, queryParams);
		if (user == null) {
			throw new UserNotExistException();
		}
		user.setPassword(newPass);
		update(user);
		return true;
	}

	/**
	 * 修改用户简介
	 *
	 * @param id
	 * @param caption
	 * @return
	 */
	@Override
	@Transactional
	public boolean changeCaption(String id, String caption) {
		User user = find(User.class, id);
		if (user == null) {
			throw new UserNotExistException();
		}
		user.setUserCaption(caption);
		update(user);
		return true;
	}

	/**
	 * 提交实名认证申请
	 *
	 * @param dto
	 * @return
	 */
	@Override
	@Transactional
	public boolean verifyID(UserRealNameVerifyDto dto) {
		User user = find(User.class, dto.getId());
		if (user == null) {
			throw new UserNotExistException();
		}
		user.setIsRealNameValidated(Config.waiting_verified);
		UserRealNameVerifyDto.fillUser(user, dto);
		// user.setIsRealNameValidated(Config.waiting_verified);
		update(user);
		return true;
	}

	/**
	 * 分页查询等待实名认证的用户
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public List<User> findAuthenWherePage(UserQueryDto dto) {
		int pageSize = dto.getPageSize();
		int offset = dto.getOffset();
		List<Object> parameters = new ArrayList<Object>();
		parameters.add(Config.waiting_verified);

		StringBuffer where = new StringBuffer("");

		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" isRealNameValidated = ? ");

		if (!StringUtils.isEmpty(dto.getUserName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" userName like ? ");
			parameters.add("%" + dto.getUserName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getEmail())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" email like ? ");
			parameters.add("%" + dto.getEmail() + "%");
		}
		if (!StringUtils.isEmpty(dto.getPhoneNumber())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" phoneNumber like ? ");
			parameters.add("%" + dto.getPhoneNumber() + "%");
		}

		List<User> result = queryByWherePage(User.class, where.toString(), CommonUtil.listToArray(parameters), offset,
				pageSize);
		return result;
	}

	@Override
	public List<User> findAuthenedWherePage(UserQueryDto dto) {
		int pageSize = dto.getPageSize();
		int offset = dto.getOffset();
		List<Object> parameters = new ArrayList<Object>();
		parameters.add(Config.verifed);

		StringBuffer where = new StringBuffer("");

		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" isRealNameValidated = ? ");

		if (!StringUtils.isEmpty(dto.getUserName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" userName like ? ");
			parameters.add("%" + dto.getUserName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getEmail())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" email like ? ");
			parameters.add("%" + dto.getEmail() + "%");
		}
		if (!StringUtils.isEmpty(dto.getPhoneNumber())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" phoneNumber like ? ");
			parameters.add("%" + dto.getPhoneNumber() + "%");
		}
		List<User> result = queryByWherePage(User.class, where.toString(), CommonUtil.listToArray(parameters), offset,
				pageSize);
		return result;
	}

	/**
	 * 返回等待实名认证的用户总条数
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public long findCountAuthen(UserQueryDto dto) {
		List<Object> parameters = new ArrayList<Object>();
		parameters.add(Config.waiting_verified);

		StringBuffer where = new StringBuffer("");

		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" isRealNameValidated = ? ");
		if (!StringUtils.isEmpty(dto.getUserName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" userName like ? ");
			parameters.add("%" + dto.getUserName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getEmail())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" email like ? ");
			parameters.add("%" + dto.getEmail() + "%");
		}
		if (!StringUtils.isEmpty(dto.getPhoneNumber())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" phoneNumber like ? ");
			parameters.add("%" + dto.getPhoneNumber() + "%");
		}
		return getCountByWhere(User.class, where.toString(), CommonUtil.listToArray(parameters));

	}

	/**
	 * 返回实名认证的用户总条数
	 * 
	 * @param dto
	 * @return
	 */
	public long findCountAuthened(UserQueryDto dto) {
		List<Object> parameters = new ArrayList<Object>();
		parameters.add(Config.verifed);

		StringBuffer where = new StringBuffer("");

		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" isRealNameValidated = ? ");
		if (!StringUtils.isEmpty(dto.getUserName())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" userName like ? ");
			parameters.add("%" + dto.getUserName() + "%");
		}
		if (!StringUtils.isEmpty(dto.getEmail())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" email like ? ");
			parameters.add("%" + dto.getEmail() + "%");
		}
		if (!StringUtils.isEmpty(dto.getPhoneNumber())) {
			if (where.length() > 0) {
				where.append(" AND ");
			}
			where.append(" phoneNumber like ? ");
			parameters.add("%" + dto.getPhoneNumber() + "%");
		}
		return getCountByWhere(User.class, where.toString(), CommonUtil.listToArray(parameters));
	}

	/**
	 * 修改用户头像
	 *
	 * @param userId
	 * @param avatarFilePath
	 * @return
	 */
	@Override
	@Transactional
	public boolean changeAvatar(String userId, String avatarFilePath) {
		User user = find(User.class, userId);
		if (user == null) {
			throw new UserNotExistException();
		}
		user.setAvatar(avatarFilePath);
		update(user);
		return true;
	}

	/**
	 * 修改用户邮件
	 *
	 * @param userId
	 * @param email
	 * @return
	 */
	@Override
	@Transactional
	public boolean changeEmail(String userId, String email) {
		User user = find(User.class, userId);
		if (user == null) {
			throw new UserNotExistException();
		}

		Object[] parameters = { userId, email };

		StringBuffer where = new StringBuffer("");

		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" id != ? ");
		where.append(" AND email = ? ");

		long count = getCountByWhere(User.class, where.toString(), parameters);
		// email已经被别的用户占用了
		if (count > 0) {
			throw new DuplicatedEmailException();
		}

		user.setEmail(email);
		update(user);
		return true;
	}

	/**
	 *
	 * 修改用户手机号
	 *
	 * @param userId
	 * @param mobile
	 * @return
	 *
	 */
	@Override
	@Transactional
	public boolean changeMobile(String userId, String mobile) {
		User user = find(User.class, userId);
		if (user == null) {
			throw new UserNotExistException();
		}

		Object[] parameters = { userId, mobile };

		StringBuffer where = new StringBuffer("");

		if (where.length() > 0) {
			where.append(" AND ");
		}
		where.append(" id != ? ");
		where.append(" AND phoneNumber = ? ");

		long count = getCountByWhere(User.class, where.toString(), parameters);
		// mobile已经被别的用户占用了
		if (count > 0) {
			throw new DuplicatedMobileException();
		}

		user.setPhoneNumber(mobile);
		update(user);
		return true;
	}

	/**
	 * 获取用户等级
	 *
	 * @param userId
	 * @return
	 */
	@Override
	@Transactional
	public Map<String, String> getUserLevel(String userId) {
		User user = find(User.class, userId);
		if (user == null) {
			throw new UserNotExistException();
		}
		Map<String, String> map = new HashMap<>();
		Object[] parameters = { userId };

		// 获取发布项目数
		long publishedProjectsCount = getCountByWhere(HoneycombProject.class, " publisher.id = ?", parameters);

		// 获取投资项目数
		String jpsql = "SELECT count(1) FROM Investment i WHERE i.user.id = ?";
		long investedProjectsCount = getCountByFullJPQL(jpsql, parameters);

		map.put("published", Long.toString(publishedProjectsCount));
		map.put("invested", Long.toString(investedProjectsCount));
		return map;
	}

	/**
	 *
	 * @param userId
	 * @param passOrNot
	 * @return
	 */
	@Transactional
	public Boolean verifyUser(String userId, Boolean passOrNot) {
		User user = find(User.class, userId);
		if (passOrNot) {
			user.setIsRealNameValidated(Config.verifed);
		} else {
			user.setIsRealNameValidated(Config.not_verified);
		}
		update(user);
		return true;
	}

	@Override
	public Person getPersonBy(String name) {
		String where = " name = ? ";
		Object[] parameters = { name };
		Person person = queryByWhereSingle(Person.class, where, parameters);
		if (person == null) {
			throw new LoginFailureException();
		}

		return person;
	}

	@Override
	public void verifyEmail(String email) {
		String fullJpql = "select count(1) from User u where u.email = ?";
		Object[] queryParams = { email };
		long email_count = getCountByFullJPQL(fullJpql, queryParams);
		if (email_count > 0) {
			throw new EmailExistException();
		}
	}

	@Override
	public SmsTemplate getSmsTemplate(String type) {
		String fullJpql = "select s from SmsTemplate s where s.type = ? and status = ?";
		Object[] queryParams = { type, true };
		List<SmsTemplate> smsTemplates = queryByFullJPQL(fullJpql, queryParams);
		if (smsTemplates.size() == 0) {
			throw new SmsTemplateNotExistException();
		}
		return smsTemplates.get(0);
	}
}
